import csv
import math
import os
from datetime import datetime

from application.config import appSettings
from application.jobs import OrderGenerationJob
from application.http.models import OemModel, CodeModel
from sanren.extensions import MyLogger
from sanren.utils.utils import Utils


log = MyLogger('order.gen.job')


def generation_job(*args, **kwargs):
    log.logger.info('===============主任务-生码')

    # 获取生码单
    obj_order = CodeModel.Order.find(args[0])
    if obj_order is None:
        log.logger.info('===============Generation Code: 找不到此生码单')
        return 700404

    # 生码单状态
    if obj_order.status not in (0, 1, 3, 4):
        log.logger.info('===============Generation Code: 已经成功或取消的生码单不能再进行生码操作')
        return 700403

    # 根据生码量进行子任务创建
    # type 1 套标 2 标准码
    if obj_order.type == 1:
        # log.logger.info('===============Generation Code: 目前不支持生套标码')

        generation_job = OrderGenerationJob(
            params={
                'counts': obj_order.counts,
                'order_id': obj_order.id,
                'order_sn': obj_order.order_sn,
                'batch_sn': obj_order.batch_sn,
                'company_code': obj_order.company_code,
            },
            log=log
        )
        generation_job.run()
        log.logger.info(f'===============Generation Code: 开始生套标码, 数量: {obj_order.counts}')
        return 700403
    elif obj_order.type == 2:
        per_count = 100000
        queue_finish_counts = 0
        if obj_order.queue_finish_counts != '' and obj_order.queue_finish_counts != None and obj_order.queue_finish_counts > 0:
            queue_finish_counts = obj_order.queue_finish_counts
        if obj_order.counts - queue_finish_counts > per_count and obj_order.counts > per_count:
            wait_gen_counts = obj_order.counts - queue_finish_counts
            range_num = math.ceil(wait_gen_counts / per_count)
            total_code_counts = 0
            for i in range(range_num):
                # 最后一次生码 数量不对
                if obj_order.counts - total_code_counts < per_count:
                    per_count = obj_order.counts - total_code_counts

                log.logger.info(f'===============子任务-生码 -- {i}')
                generation_item_job(obj_order.batch_sn, per_count)

                total_code_counts += per_count
        else:
            log.logger.info('===============子任务-生码')
            # per_count = obj_order.counts
            per_count = obj_order.counts - queue_finish_counts
            generation_item_job(obj_order.batch_sn, per_count)
    else:
        log.logger.info('===============Generation Code: 生码类型错误')
        return 700400

    # 结束任务
    generation_finish_job(obj_order.batch_sn)


def generation_item_job(*args, **kwargs):
    # 参数获取
    batch_sn = ''
    counts = 0
    if len(args) == 2:
        batch_sn, counts = args
    else:
        batch_sn = args[0]
    log.logger.info(f'==============={batch_sn}, {counts}')

    # 获取生码单
    obj_order = CodeModel.Order.where('batch_sn', batch_sn).first()
    generation_job = OrderGenerationJob(
        params={
            'counts': counts,
            'order_id': obj_order.id,
            'order_sn': obj_order.order_sn,
            'batch_sn': obj_order.batch_sn,
            'company_code': obj_order.company_code,
        },
        log=log
    )
    generation_job.run()


def generation_finish_job(*args, **kwargs):
    # 完成逻辑 判断码是否已经生完成了
    # 参数获取
    batch_sn = args[0]
    # 获取生码单
    obj_order = CodeModel.Order.where('batch_sn', batch_sn).first()

    # 完成
    if obj_order.counts == obj_order.queue_finish_counts:
        obj_order.queue_status = 2
        obj_order.queue_error_reason = None
        obj_order.status = 2
        obj_order.save()

    log.logger.info('===============任务-生码完成')


def export_job(*args, **kwargs):
    log = MyLogger('export.job')
    log.logger.info('===============任务-导出码包')

    # 下载单信息
    obj_download = OemModel.Download.find(args[0])
    if obj_download is None:
        log.logger.info('===============Export Code: 找不到此下载单')
        return 700404

    if obj_download.status == 2:
        log.logger.info('===============Export Code: 此下载单已经完成')
        return 700403

    params = kwargs
    # 获取生码单
    order = CodeModel.Order.find(params['id'])
    if order is None:
        log.logger.info('===============Export Code: 找不到此生码单')
        return 700404

    log.logger.info(f'===============Export Code: 开始处理码包 {params['id']}')
    # 下载单变更为处理中
    obj_download.status = 1
    obj_download.save()

    # 导出字段配置
    field_list = params['field_list']
    fields = field_list.split(',')
    # print(fields)
    # 前缀
    url_prefix = params['url_prefix']
    # 2022-02-21
    # if url_prefix:
    #     url_prefix = url_prefix[:-1] if url_prefix.endswith('/') else url_prefix
    # 流水号前缀
    serial_prefix = params['serial_prefix']
    serial_suffix = params['serial_suffix']
    # 类型
    file_type = params['file_type']

    # 码表
    Code = CodeModel.get_code_model(order.company_code)
    # txt csv 字段根据提交过来的元素和顺序
    # codes = CodeModel.query.filter_by(batch_sn=order.batch_sn).order_by(CodeModel.id.asc()).all()

    # _file_name = order.batch_sn + '-' + str(order.counts) + '-' + str(Utils.create_random_number(8))
    _file_name = f'{order.batch_sn}-{str(order.counts)}-{datetime.now().strftime("%Y%m%d%H%M%S")}-{str(Utils.create_random_number(6))}'
    if not os.path.exists(appSettings.export_path):
        os.makedirs(appSettings.export_path)
    file_name = _file_name + '.' + file_type
    save_file_path = appSettings.export_path + '/' + file_name

    def fetch_in_batches(batch_size):
        # 初始化一个批次计数器
        count = 0
        while True:
            # 使用session.query(Model).offset(count*batch_size).limit(batch_size)生成一个查询
            # 使用for循环迭代这个查询，因为它是惰性执行的
            obj_codes = Code.where('batch_num', order.batch_num).order_by('id', 'asc').offset(count * batch_size).limit(batch_size).get()
            for item in obj_codes:
                # 使用yield生成每一个结果
                yield item

            # 增加计数器
            count += 1

            # 如果没有更多的结果，则退出for循环
            if len(obj_codes) == 0:
                break

    def write_csv():
        # 1. 创建文件对象
        df = open(save_file_path, 'w', encoding='utf-8')
        # 2. 基于文件对象构建 csv写入对象
        csv_writer = csv.writer(df)
        # 3. 构建列表头
        csv_writer.writerow(format_code_header(fields))
        # 4. 写入csv文件内容
        # for item in codes:
        for item in fetch_in_batches(100000):
            row = format_code(fields, item)
            csv_writer.writerow(row)
        # 5. 关闭文件
        df.close()

    def format_code_header(fields):
        headers = {
            'big_code': '大标',
            'middle_code': '中标',
            'small_code': '刮刮码',
            'serial_code': '流水号',
            'security_code': '防伪码',
            'verify_code': 'PIN码',
            'prefix_serial_code': '流水号',
            'prefix_serial_code_ewm': '流水二维码',
            'prefix_security_code': '二维码',
        }
        write_data = []
        for field in fields:
            if field in headers.keys():
                write_data.append(headers[field])
        return write_data

    def format_code(fields, data):
        write_data = []
        data = data.serialize()
        for field in fields:
            if field == 'verify_code':
                serial_str = 'PIN:' + data['verify_code']
                write_data.append(serial_str)
            elif field == 'prefix_serial_code':
                serial_str = serial_prefix + data['serial_code'] + serial_suffix
                write_data.append(serial_str)
            elif field == 'prefix_serial_code_ewm':
                serial_str = url_prefix + serial_prefix + data['serial_code'] + serial_suffix
                write_data.append(serial_str)
            elif field == 'prefix_security_code':
                # 2022-02-21
                if order.query_type == 3:
                    # url = url_prefix + '/' + data['security_code']
                    url = url_prefix + data['security_code']
                else:
                    # url = url_prefix + '/' + data['batch_sn'] + '-' + data['security_code']
                    url = url_prefix + data['batch_sn'] + '-' + data['security_code']
                write_data.append(url)
            elif field in data:
                write_data.append(data[field])
        return write_data

    try:
        # 生成码包文件
        write_csv()
    except Exception as e:
        log.logger.error(f'===============任务-导出码包失败, {e}')
        obj_download.status = 3
        obj_download.save()

    # 下载单
    obj_download.path = file_name
    obj_download.status = 2
    obj_download.save()

    log.logger.info('===============任务-导出完成')
